package com.example.srb.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.srb.common.exception.Assert;
import com.example.srb.common.result.ResponseEnum;
import com.example.srb.core.enums.TransTypeEnum;
import com.example.srb.core.hfb.FormHelper;
import com.example.srb.core.hfb.HfbConst;
import com.example.srb.core.hfb.RequestHelper;
import com.example.srb.core.mapper.UserInfoMapper;
import com.example.srb.core.pojo.bo.TransFlowBO;
import com.example.srb.core.pojo.entity.UserAccount;
import com.example.srb.core.mapper.UserAccountMapper;
import com.example.srb.core.pojo.entity.UserInfo;
import com.example.srb.core.service.TransFlowService;
import com.example.srb.core.service.UserAccountService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.srb.core.service.UserBindService;
import com.example.srb.core.service.UserInfoService;
import com.example.srb.core.util.LendNoUtils;
import com.example.srb.rabbitmq.constant.MQConst;
import com.example.srb.rabbitmq.service.MQService;
import com.example.srb.service2base.dto.SmsDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 用户账户 服务实现类
 * </p>
 *
 * @author Helen
 * @since 2021-02-20
 */
@Service
@Slf4j
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements UserAccountService {

    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private UserAccountMapper userAccountMapper;
    @Resource
    private TransFlowService transFlowService;
    @Resource
    private UserAccountService userAccountService;
    @Resource
    private UserBindService userBindService;
    @Resource
    private MQService mqService;
    @Resource
    private UserInfoService userInfoService;

    @Override
    public String commitCharge(BigDecimal chargeAmt, Long userId) {

        UserInfo userInfo = userInfoMapper.selectById(userId);

        //判断账户绑定状态
        String bindCode = userInfo.getBindCode();
        Assert.notEmpty(bindCode, ResponseEnum.USER_NO_BIND_ERROR);

        //生成用户地址请求
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);//商户分配的唯一标识
        paramMap.put("agentBillNo", LendNoUtils.getNo());//商户充值单号（唯一）
        paramMap.put("bindCode",bindCode);//充值人绑定协议号
        paramMap.put("chargeAmt",chargeAmt);//充值金额
        paramMap.put("feeAmt",new BigDecimal("0"));//商户收取的手续费
        paramMap.put("notifyUrl",HfbConst.RECHARGE_NOTIFY_URL);//通知商户充值成功的完整地址
        paramMap.put("returnUrl",HfbConst.RECHARGE_RETURN_URL);//充值完成后同步返回商户的完整地址
        paramMap.put("timestamp", RequestHelper.getTimestamp());//时间戳

        String sign = RequestHelper.getSign(paramMap);
        paramMap.put("sign",sign);//验签参数

        //构建充值自动提交表单
        String formStr = FormHelper.buildForm(HfbConst.RECHARGE_URL, paramMap);
        return formStr;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String notify(Map<String, Object> paramMap) {

        log.info("充值成功！" + JSONObject.toJSONString(paramMap));

        String bindCode = (String)paramMap.get("bindCode");//充值人绑定协议号
        String chargeAmt = (String)paramMap.get("chargeAmt");//充值金额
        String  agentBillNo = (String) paramMap.get("agentBillNo");//商户充值订单号

        //幂等性判断？标准 =  //判断交易流水是否存在
        Boolean isSave = transFlowService.isSaveTransFlow(agentBillNo);
        if (isSave){
            log.warn("幂等性返回");
            return "success";
        }

        //账户处理
        userAccountMapper.updateAccount(bindCode,new BigDecimal(chargeAmt),new BigDecimal(0));

        //增加交易流水
        TransFlowBO transFlowBO = new TransFlowBO();
        transFlowBO.setAgentBillNo(agentBillNo);
        transFlowBO.setBindCode(bindCode);
        transFlowBO.setAmount(new BigDecimal(chargeAmt));
        transFlowBO.setTransTypeEnum(TransTypeEnum.RECHARGE);
        transFlowBO.setMemo("充值");
        transFlowService.saveTransFlow(transFlowBO);

        //向rabbitmq发送消息
        String mobile = userInfoService.getMobileByBindcode(bindCode);
        SmsDTO smsDTO = new SmsDTO();
        smsDTO.setMobile(mobile);
        smsDTO.setMessage("充值" +transFlowBO.getAmount()+ "元成功");
        mqService.sendMessage(
                MQConst.EXCHANGE_TOPIC_SMS,
                MQConst.ROUTING_SMS_ITEM,
                smsDTO
        );

        return "success";
    }

    @Override
    public BigDecimal getAccount(Long userId) {
        QueryWrapper<UserAccount> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId);
        UserAccount userAccount = baseMapper.selectOne(wrapper);
        return userAccount.getAmount();
    }

    @Override
    public String commitWithdraw(BigDecimal fetchAmt, Long userId) {
        //账户可用余额充足：当前用户的余额 >= 当前用户的提现金额
        BigDecimal account = userAccountService.getAccount(userId);
        Assert.isTrue(account.doubleValue() >= fetchAmt.doubleValue(),ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);

        String bindCode = userBindService.getBindCodeByUserId(userId);
        //构建自动提交表单
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("agentId",HfbConst.AGENT_ID);//给商户分配的唯一标识
        paramMap.put("agentBillNo",LendNoUtils.getWithdrawNo());//商户提现单号
        paramMap.put("bindCode",bindCode);//用户绑定协议号
        paramMap.put("fetchAmt",fetchAmt);//提现金额
        paramMap.put("feeAmt",new BigDecimal(0));//商户收取用户的手续费
        paramMap.put("returnUrl",HfbConst.WITHDRAW_RETURN_URL);
        paramMap.put("notifyUrl",HfbConst.WITHDRAW_NOTIFY_URL);
        paramMap.put("timestamp",RequestHelper.getTimestamp());//时间戳
        paramMap.put("sign",RequestHelper.getSign(paramMap));//验签参数。

        return FormHelper.buildForm(HfbConst.WITHDRAW_URL,paramMap);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void notifyWithdraw(Map<String, Object> paramMap) {
        log.info("提现成功");
        //幂等性判断
        String agentBillNo = (String) paramMap.get("agentBillNo");
        Boolean flag = transFlowService.isSaveTransFlow(agentBillNo);
        if (flag){
            log.warn("幂等性返回");
            return;
        }

        //提现修改金额
        String bindCode = (String) paramMap.get("bindCode");
        String fetchAmt = (String) paramMap.get("fetchAmt");
        baseMapper.updateAccount(bindCode,new BigDecimal( "-" + fetchAmt),new BigDecimal(0));

        //增加交易流水
        TransFlowBO transFlowBO = new TransFlowBO(agentBillNo,
                bindCode,new BigDecimal(fetchAmt) ,TransTypeEnum.WITHDRAW,
                "提现");
        transFlowService.saveTransFlow(transFlowBO);

    }
}
